package fem2;

import inf.jlinalg.IVector;
import inf.jlinalg.SolveFailedException;
import inf.text.ArrayFormat;
import junit.framework.Assert;
import math2.FunctionRnToR;
import math2.RampFunctionRToR;

import org.junit.Test;

import fem2.analysis.Analysis;
import fem2.analysis.LinearStaticAnalysis;
import fem2.element.ESfemStructuralElement;
import fem2.element.StructuralElement;
import fem2.enu.EchoLevelType;
import fem2.enu.SolverType;
import fem2.enu.State;
import fem2.material.ESfemManager;
import fem2.material.StVenantKirchhoffMM;
import fem2.strategies.ArcLengthSolutionStrategyWithSphereConstraint;

public class PatchTestT3ESfem {

	public PatchTestT3ESfem() {
	}

	public Mesh createMesh() {
		return new PatchTestT3(0).createMesh(0.5, 0.5);
		// return new PatchTestT3(0).createMesh();
	}

	public Model createModel() {
		Mesh mesh = createMesh();

		double E = 2;
		double nu = 0.3;
		double t = 1.0;
		State ss = State.PLANE_STRESS;
		MaterialModel mm = new StVenantKirchhoffMM(E, nu, t, 0, ss);

		Model m = new Model(mesh);
		MaterialModel mm1 = new ESfemManager(m, mm);

		for (int i = 0; i < mesh.countFaces(); i++) {
			Element e = new ESfemStructuralElement(mesh.getFace(i), mm1);
			m.addElement(e);
		}

		return m;
	}

	@Test
	public void testSolve1() throws SolveFailedException {
		double F = 0.5;
		Model m = createModel();
		Force l1 = new Force(m.getMesh().getNode(1), F, 0);
		Force l2 = new Force(m.getMesh().getNode(2), F, 0);
		m.addLoad(l1);
		m.addLoad(l2);

		ESfemManager mm1 = (ESfemManager) ((StructuralElement) m.getElement(0)).getMaterialModel();

		Analysis an = new LinearStaticAnalysis(m);
		an.getStrategy().addObserver((ESfemManager) mm1);
		an.getStrategy().setSolverType(SolverType.BAITSCH_SOLVER_GENERIC);
		an.getStrategy().setEchoLevel(EchoLevelType.DEBUG);

		an.run();

		/*
		 * print the displacement and check with theoretical values
		 */
		System.out.println("testSolve1 results:");
		// double[][] Uh = new double[][] { { 0, 0 }, { 0.5, 0 }, { 0.5, -0.15
		// }, { 0, -0.15 } };
		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			System.out.println(ArrayFormat.format(uHatLocal));
			// Assert.assertEquals(Uh[i][0], uHatLocal[0], 1e-10);
			// Assert.assertEquals(Uh[i][1], uHatLocal[1], 1e-10);
		}

		// for (int i = 0; i < m.countElements(); i++) {
		// StructuralElement e = (StructuralElement) m.getElement(i);
		// for (int j = 0; j < e.getNumIntegrationPoints(); j++) {
		// IVector sigma = e.getStress(j);
		// Assert.assertEquals(1.0, sigma.get(0), 1e-10);
		// Assert.assertEquals(0.0, sigma.get(1), 1e-10);
		// Assert.assertEquals(0.0, sigma.get(2), 1e-10);
		// }
		// }
	}

	@Test
	public void testSolve2() throws SolveFailedException {
		double F = 1;
		Model m = createModel();
		Mesh mesh = m.getMesh();

		FunctionRnToR ld = new RampFunctionRToR(-1, 1, F, F);
		Load el = new DistributedLoad(mesh.getEdge(0), ld, null);
		m.addLoad(el);

		double[] re = el.computeRe(0.0);
		System.out.println("re =" + ArrayFormat.format(re));

		Analysis an = new LinearStaticAnalysis(m);
		an.run();

		/*
		 * print the displacement and check with theoretical values
		 */
		System.out.println("testSolve2 results:");
		double[][] Uh = new double[][] { { 0, 0 }, { 0.5, 0 }, { 0.5, -0.15 }, { 0, -0.15 } };
		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			System.out.println(ArrayFormat.format(uHatLocal));
		}
		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			Assert.assertEquals(Uh[i][0], uHatLocal[0], 1e-10);
			Assert.assertEquals(Uh[i][1], uHatLocal[1], 1e-10);
		}

		for (int i = 0; i < m.countElements(); i++) {
			StructuralElement e = (StructuralElement) m.getElement(i);
			for (int j = 0; j < e.getNumIntegrationPoints(); j++) {
				IVector sigma = e.getStress(j);
				Assert.assertEquals(1.0, sigma.get(0), 1e-10);
				Assert.assertEquals(0.0, sigma.get(1), 1e-10);
				Assert.assertEquals(0.0, sigma.get(2), 1e-10);
			}
		}
	}

	@Test
	public void testSolve3() throws SolveFailedException {
		Model m = createModel();
		Mesh mesh = m.getMesh();

		double du = 0.5;
		Constraint c1 = new Constraint(false, false);
		c1.setValue(0, du);
		mesh.getNode(1).setConstraint(c1);
		Constraint c2 = new Constraint(false, true);
		c2.setValue(0, du);
		mesh.getNode(2).setConstraint(c2);

		Analysis an = new LinearStaticAnalysis(m);
		an.run();

		/*
		 * print the displacement and check with theoretical values
		 */
		System.out.println("testSolve3 results:");
		double[][] Uh = new double[][] { { 0, 0 }, { 0.5, 0 }, { 0.5, -0.15 }, { 0, -0.15 } };
		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			System.out.println(ArrayFormat.format(uHatLocal));
			Assert.assertEquals(Uh[i][0], uHatLocal[0], 1e-10);
			Assert.assertEquals(Uh[i][1], uHatLocal[1], 1e-10);
		}

		for (int i = 0; i < m.countElements(); i++) {
			StructuralElement e = (StructuralElement) m.getElement(i);
			for (int j = 0; j < e.getNumIntegrationPoints(); j++) {
				IVector sigma = e.getStress(j);
				Assert.assertEquals(1.0, sigma.get(0), 1e-10);
				Assert.assertEquals(0.0, sigma.get(1), 1e-10);
				Assert.assertEquals(0.0, sigma.get(2), 1e-10);
			}
		}
	}

	@Test
	public void testSolve4() throws SolveFailedException {
		double F = 0.5;
		Model m = createModel();
		Force l1 = new Force(m.getMesh().getNode(1), F, 0);
		Force l2 = new Force(m.getMesh().getNode(2), F, 0);
		m.addLoad(l1);
		m.addLoad(l2);

		Analysis an = new Analysis(m);

		an.setStrategy(new ArcLengthSolutionStrategyWithSphereConstraint(m, 0.1, 0.0));
		an.getStrategy().setEchoLevel(EchoLevelType.DEBUG, EchoLevelType.OUTPUT);
		an.getStrategy().setNumberOfTimeStep(10);

		an.run();

		/*
		 * print the displacement and check with theoretical values
		 */
		System.out.println("testSolve4 results:");
		// double[][] Uh = new double[][] { { 0, 0 }, { 0.5, 0 }, { 0.5, -0.15
		// }, { 0, -0.15 } };
		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			System.out.println(ArrayFormat.format(uHatLocal));
			// Assert.assertEquals(Uh[i][0], uHatLocal[0], 1e-10);
			// Assert.assertEquals(Uh[i][1], uHatLocal[1], 1e-10);
		}
	}

	// public static void main(String[] args) throws SolveFailedException {
	// Model m = new PatchTestT3ESfem().createModel();
	// Viewer v = new Viewer(m);
	// v.setVisible(true);
	// }
}
